from selenium import webdriver
import time
from PIL import Image
import ddddocr
import cv2
from selenium.webdriver import ActionChains

options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(options=options)
driver.maximize_window()

for i in range(1, 100):
    # 触发验证码
    driver.get('https://www.bilibili.com/')
    time.sleep(5)
    driver.find_element_by_xpath("//div[@class='header-login-entry']").click()
    time.sleep(2)
    driver.find_element_by_xpath("//div[@class='form__item'][1]/input").send_keys("12345678")
    driver.find_element_by_xpath("//div[@class='form__item'][2]/input").send_keys("12345678")
    time.sleep(1)
    driver.find_element_by_xpath("//div[@class='btn_primary ']").click()
    time.sleep(3)

    # 截取验证码文字图片
    check_code_img = driver.find_element("xpath", "//div[@class='geetest_tip_img']")
    check_code_img.screenshot(f"word{i}.png")

    # 识别文字
    ocr = ddddocr.DdddOcr(beta=True)
    image = open(f"word{i}.png", "rb").read()
    result = ocr.classification(image)
    print(result)

    # 截取验证码背景图片
    check_code_img = driver.find_element("xpath", "//div[@class='geetest_item_wrap']")
    check_code_img.screenshot(f"bg{i}.png")

    # 目标检测
    det = ddddocr.DdddOcr(det=True)
    with open(f"bg{i}.png", 'rb') as f:
        image = f.read()
    bboxes = det.detection(image)
    print(bboxes)

    # 把结果在图片上做一个标注
    im = cv2.imread(f"bg{i}.png")
    for bbox in bboxes:
        x1, y1, x2, y2 = bbox
        im = cv2.rectangle(im, (x1, y1), (x2, y2), color=(0, 0, 255), thickness=2)
    cv2.imwrite(f"result{i}.jpg", im)

    # 如果文字检测数量和目标盒子数量不一致的话进行重试
    if len(result) != len(bboxes):
        continue

    # 计算点击顺序 扣出目标位置的所有字 打上序号进行识别 然后和目标点击顺序进行对照
    index = 0
    click_index_dict = {}
    for bbox in bboxes:
        index += 1
        bg_img = Image.open(f"bg{i}.png")
        char_img = bg_img.crop(bbox)
        char_img.save(f"char{i}-{index}.png")
        # 识别每个字 计算点击顺序
        char_result = ocr.classification(char_img)
        print("单个字符的识别结果：", char_result)
        # 获取单个字符的索引
        find_index = result.find(char_result)
        click_index_dict[find_index] = bbox
    print(click_index_dict)

    # 如果字典长度和识别结果长度对不上说明 单字识别错误超过一个 进行重试
    if len(click_index_dict.items()) != len(result):
        continue

    temp = -1
    # -1索引替换为缺失索引
    for i in range(len(result)):
        if i not in list(click_index_dict.keys()):
            temp = i
            break
    if temp != -1:
        # 修改字典-1索引
        click_index_dict[temp] = click_index_dict[-1]
        del click_index_dict[-1]

    # 对字典索引进行排序然后进行点击
    click_index_dict = sorted(click_index_dict.items(), key=lambda x: x[0])
    for key, bbox in click_index_dict:
        x = (bbox[0] + bbox[2]) / 2
        y = (bbox[1] + bbox[3]) / 2
        print("每个目标位置的点击中心位置：", x, y)
        ActionChains(driver).move_to_element_with_offset(check_code_img, x, y).click().perform()
        time.sleep(1)
    driver.find_element_by_xpath("//a[@class='geetest_commit']").click()

    # 验证验证码是否识别成功
    break
